home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / DEMON / RISCOS2 / TCP_131S.ARC / c / ICMP < prev    next >
Text File  |  1994-01-08  |  6KB  |  202 lines

  1. /* Internet Control Message Protocol */
  2. #include "global.h"
  3. #include "mbuf.h"
  4. #include "misc.h"
  5. #include "internet.h"
  6. #include "timer.h"
  7. #include "iface.h"
  8. #include "ip.h"
  9. #include "netuser.h"
  10. #include "tcp.h"
  11. #include "udp.h"
  12. #include "icmp.h"
  13.  
  14. struct icmp_errors icmp_errors;
  15. struct icmp_stats icmp_stats;
  16.  
  17. /* Process an incoming ICMP packet */
  18. void icmp_input(struct mbuf *bp, char protocol, int32 source,
  19.                 int32 dest, char tos, int16 length, char rxbroadcast)
  20. {
  21.   struct mbuf *tbp;
  22.   struct icmp icmp;       /* ICMP header */
  23.   struct ip ip;           /* Offending datagram header */
  24.   int16 type;             /* Type of ICMP message */
  25.   struct udp udphdr;
  26.  
  27.   protocol = protocol;
  28.  
  29.   if(rxbroadcast)
  30.   {
  31.           /* Broadcast ICMP packets are to be IGNORED !! */
  32.           icmp_errors.bdcsts++;
  33.           free_p(bp);
  34.           return;
  35.   }
  36.   if(cksum(NULLHEADER,bp,length) != 0)
  37.   {
  38.           /* Bad ICMP checksum; discard */
  39.           icmp_errors.checksum++;
  40.           free_p(bp);
  41.           return;
  42.   }
  43.   ntohicmp(&icmp,&bp);
  44.  
  45.   /* Process the message. Some messages are passed up to the protocol
  46.    * module for handling, others are handled here.
  47.    */
  48.   type = icmp.type;
  49.   if (type < ICMP_TYPES)
  50.     icmp_stats.input[type]++;
  51.  
  52.   switch(uchar(type))
  53.   {
  54.   case TIME_EXCEED:       /* Time-to-live Exceeded */
  55.   case DEST_UNREACH:      /* Destination Unreachable */
  56.   case QUENCH:            /* Source Quench */
  57.     ntohip(&ip, &bp);     /* Extract offending IP header */
  58.     switch(uchar(ip.protocol))
  59.     {
  60.     case TCP_PTCL:
  61.       tcp_icmp(ip.source,ip.dest,icmp.type,icmp.code,&bp);
  62.       break;
  63.     case UDP_PTCL:
  64.       if (uchar(type) == TIME_EXCEED || uchar(type) == DEST_UNREACH)
  65.       {
  66.         ntohudp(&udphdr,&bp);
  67.         hop_rec(&icmp, &udphdr, source, type);
  68.       }
  69.       break;
  70.     }
  71.     break;
  72.   case ECHO:              /* Echo Request */
  73.     /* Change type to ECHO_REPLY, recompute checksum,
  74.        and return datagram. */
  75.     icmp.type = ECHO_REPLY;
  76.     if((tbp = htonicmp(&icmp,bp)) == NULLBUF)
  77.     {
  78.       free_p(bp);
  79.       return;
  80.     }
  81.     icmp_stats.output[ECHO_REPLY]++;
  82.     ip_send(dest,source,ICMP_PTCL,tos,0,tbp,length,0,0);
  83.     return;
  84.   case REDIRECT:          /* Redirect */
  85.   case PARAM_PROB:        /* Parameter Problem */
  86.     break;
  87.   case ECHO_REPLY:         /* Echo Reply */
  88.     echo_proc(source,dest,&icmp);
  89.     break;
  90.   case TIMESTAMP:         /* Timestamp */
  91.   case TIME_REPLY:        /* Timestamp Reply */
  92.   case INFO_RQST:         /* Information Request */
  93.   case INFO_REPLY:        /* Information Reply */
  94.     break;
  95.   }
  96.   free_p(bp);
  97. }
  98. /* Return an ICMP response to the sender of a datagram.
  99.    Unlike most routines, the callER frees the mbuf. */
  100. int icmp_output(struct ip *ip, struct mbuf *data, char type, char code,
  101.                 union icmp_args *args)
  102. {
  103.         struct mbuf *bp;
  104.         struct icmp icmp;       /* ICMP protocol header */
  105.         int16 dlen;             /* Length of data portion of offending pkt */
  106.         int16 length;           /* Total length of reply */
  107.         extern int32 ip_addr;   /* Our IP address */
  108.  
  109.         if(ip == NULLIP)
  110.                 return -1;
  111.         if(type < ICMP_TYPES)
  112.                 icmp_stats.output[type]++;
  113.  
  114.         if(uchar(ip->protocol) == ICMP_PTCL)
  115.         {
  116.                 /* Never send an ICMP message about another ICMP message */
  117.                 icmp_errors.noloop++;
  118.                 return -1;
  119.         }
  120.         /* Compute amount of original datagram to return.
  121.          * We return the original IP header, and up to 8 bytes past that.
  122.          */
  123.         dlen = min(8,len_mbuf(data));
  124.         length = dlen + ICMPLEN + IPLEN + ip->optlen;
  125.         /* Take excerpt from data portion */
  126.         if(data != NULLBUF && (bp = copy_p(data,dlen)) == NULLBUF)
  127.                 return -1;      /* The caller will free data */
  128.  
  129.         /* Recreate and tack on offending IP header */
  130.         if((data = htonip(ip,bp)) == NULLBUF)
  131.         {
  132.                 free_p(bp);
  133.                 return -1;
  134.         }
  135.         icmp.type = type;
  136.         icmp.code = code;
  137.         switch(uchar(icmp.type))
  138.         {
  139.         case PARAM_PROB:
  140.                 icmp.args.pointer = args->pointer;
  141.                 break;
  142.         case REDIRECT:
  143.                 icmp.args.address = args->address;
  144.                 break;
  145.         case ECHO:
  146.         case ECHO_REPLY:
  147.         case INFO_RQST:
  148.         case INFO_REPLY:
  149.         case TIMESTAMP:
  150.         case TIME_REPLY:
  151.                 icmp.args.echo.id = args->echo.id;
  152.                 icmp.args.echo.seq = args->echo.seq;
  153.                 break;
  154.         default:
  155.                 icmp.args.unused = 0;
  156.                 break;
  157.         }
  158.         /* Now stick on the ICMP header */
  159.         if((bp = htonicmp(&icmp,data)) == NULLBUF)
  160.         {
  161.                 free_p(data);
  162.                 return -1;
  163.         }
  164.         return ip_send(ip_addr,ip->source,ICMP_PTCL,ip->tos,0,bp,length,0,0);
  165. }
  166. /* Generate ICMP header in network byte order, link data, compute checksum */
  167. struct mbuf *htonicmp(struct icmp *icmp, struct mbuf *data)
  168. {
  169.         struct mbuf *bp;
  170.         register char *cp;
  171.         int16 checksum;
  172.  
  173.         if((bp = pushdown(data,ICMPLEN)) == NULLBUF)
  174.                 return NULLBUF;
  175.         cp = bp->data;
  176.  
  177.         *cp++ = icmp->type;
  178.         *cp++ = icmp->code;
  179.         cp = put16(cp,0);               /* Clear checksum */
  180.         cp = put16(cp,icmp->args.echo.id);
  181.         cp = put16(cp,icmp->args.echo.seq);
  182.  
  183.         /* Compute checksum, and stash result */
  184.         checksum = cksum(NULLHEADER,bp,len_mbuf(bp));
  185.         cp = &bp->data[2];
  186.         cp = put16(cp,checksum);
  187.  
  188.         return bp;
  189. }
  190. /* Pull off ICMP header */
  191. int ntohicmp(struct icmp *icmp, struct mbuf **bpp)
  192. {
  193.         if(icmp == (struct icmp *)NULL)
  194.                 return -1;
  195.         icmp->type = pullchar(bpp);
  196.         icmp->code = pullchar(bpp);
  197.         (void) pull16(bpp);             /* Toss checksum */
  198.         icmp->args.echo.id = pull16(bpp);
  199.         icmp->args.echo.seq = pull16(bpp);
  200.         return 0;
  201. }
  202.